Object Pascal

Эта статья находится на начальном уровне проработки, в одной из её версий выборочно используется текст из источника, распространяемого под свободной лицензией
Материал из энциклопедии Руниверсалис
Object Pascal
Тип исполнения компилируемый
Система типов статическая, динамическая (array of const, RTTI, Variant), строгая
Основные реализации Delphi (x86 and CLI), Oxygene (CLI), Free Pascal (x86, x86-64, PowerPC, ppc64, SPARC and ARM), Virtual Pascal (x86), TMT Pascal (x86), Turbo51 (Intel 8051)
Диалекты Apple, Turbo Pascal, objfpc, Delphi, Delphi.NET, Oxygene
Повлиял на C#, Java, Nim

Object Pascal (с англ. — «Объектный Паскаль») — язык программирования, разработанный в фирме Apple Computer в 1986 году группой Ларри Теслера, который консультировался с Никлаусом Виртом[1]. Произошёл от более ранней объектно-ориентированной версии Паскаль[2], называвшейся Clascal, который был доступен на компьютере Apple Lisa.

Изменения в Object Pascal от Borland в сравнении с Turbo Pascal

Изменения коснулись групп целых, символьных и строковых типов, которые стали разделяться на две категории:

  • Фундаментальные (fundamental) типы. Их представление в памяти (число битов и наличие знака) строго фиксируется и выдерживается неизменным во всех последующих реализациях Object Pascal для любых операционных систем и компьютерных платформ.
  • Родовые (generic) типы. Их представление в памяти не фиксируется и будет реализовано оптимальным способом, в зависимости от реализации для конкретной операционной системы и компьютерной платформы.

Интерфейсы

См. Интерфейсы: Delphi

Перегрузка процедур и функций (не ООП)

Введена перегрузка процедур и функций, не являющихся членами объекта или класса. Перегружаются (с помощью ключевого слова overload) отличающиеся типами и числом параметров процедуры и функции:

procedure Calc(I: Integer); overload;
// ...
procedure Calc(S: String; J: Integer); overload;

Динамический массив

Введён для устранения рутинных операций выделения и возвращения памяти в heap-область (кучу), и для того, чтобы избежать случайных ошибок и утечки памяти. Элементы массива должны быть одинаковыми по типу. Нумерация элементов начинается с нуля.

Пример объявления:

var MyFlexibleArray: array of Real;

Использование:

var
  A, B: array of Integer;
begin
  SetLength(A, 1); //Выделяем память под один элемент
  A[0] := 1;   B := A;
  B[0] := 2;
end;

Начиная с Delphi XE7 стали возможны следующие действия с динамическими массивами:

var M: array of integer;
begin
  M := [1, 2, 3, 4, 5];
end;

 M := M + [5, 6, 7];
 Insert([6, 7, 8], M, 5); // вставка массива [6, 7, 8], в M, начиная с индекса 5
 Delete(M, 1, 3); // удаляем 3 элемента, начиная с индекса 1
 Concat([1, 2, 3, 4], [5, 6, 7])

То есть с динамическими массивами можно работать так же, как со строками.

В динамическом массиве также возможно задание открытого массива параметров, но тип их должен быть объявлен ранее, например:

type TDynamicCharArray = array of Char;
function Find(A: TDynamicCharArray): Integer;

Динамическая типизация

Операторы динамической проверки и приведения типов

В языке Object Pascal фирмы Borland появилась динамическая типизация, а также оператор динамического приведения типов as и оператор is для динамической проверки типов. Также в открытом массиве параметров стала возможна передача параметров различного типа (variant open array parameters).

Вариантный тип

В языке Object Pascal был введён вариантный тип данных (Variant), тип которых не известен на этапе компиляции и может изменяться на этапе выполнения программы. Однако этот тип данных поглощает больше памяти по сравнению с соответствующими переменными и операции над данными типа Variant выполняются медленнее. Более того, недопустимые операции над данными этого типа чаще приводят к ошибкам на этапе выполнения программы, в то время как подобные ошибки над данными другого типа были бы выявлены ещё на этапе компиляции.

Вариантные переменные могут принимать различные значения (целые, строковые, булевские, Currency, OLE-строки), быть массивами элементов этих же типов и массивом значений вариантного типа, а также содержать COM и CORBA объекты, чьи методы и свойства могут быть доступны посредством этого типа. Однако Variant не может содержать:

  • данные структурных типов;
  • указатели;
  • Int64 (начиная с Delphi 6 — может).

Variant можно смешивать (в выражениях и операторах) с другими вариантами, числовыми, строковыми и булевскими данными. При этом компилятор автоматически выполняет преобразование типа. Варианты, содержащие строки, не могут, однако, индексироваться (V[i] не допустимо).

var
  V1, V2, V3, V4, V5: Variant;
  I: Integer;
  D: Double;
  S: String;
begin
  V1 := 1; //значение типа integer
  V2 := 359.768; //значение типа real
  V3 := 'Hello world!'; //значение типа string
end;

Параметры типа вариантного открытого массива

Стала возможна передача параметров различного типа. В оригинале он назван как «variant open array parameters». Тип данных определяется динамически в процессе выполнения программы. Так же как и в обычном открытом массиве функция High вызывается для определения числа элементов массива. Для объявления используются ключевые слова array of const. Пример:

function Output(const Args: array of const): string;
var
  I: Integer;
begin
  Result := '';
  for I := 0 to High(Args) do with Args[I] do
    case VType of
      vtString:     Result := Result + VString^;
      vtPChar:      Result := Result + VPChar;
      vtInteger:    Result := Result + IntToStr(VInteger);
      vtBoolean:    Result := Result + BoolToStr(VBoolean);
      vtChar:       Result := Result + VChar;
      vtExtended:   Result := Result + FloatToStr(VExtended^);
      vtObject:     Result := Result + VObject.ClassName;
      vtClass:      Result := Result + VClass.ClassName;
      vtVariant:    Result := Result + string(VVariant^);
      vtInt64:      Result := Result + IntToStr(VInt64^);
      vtAnsiString: Result := Result + string(VAnsiString);
      vtCurrency:   Result := Result + CurrToStr(VCurrency^);
    end;

  Result := Result + ' ';
end;
//...

Output(['test', 777, '@', True, 3.14159, TForm]); //передача открытого массива параметров

Будет возвращена строка: «test 777 @ T 3.14159 TForm».

Как видно, имеет свою внутреннюю структуру, обращение к которой даёт возможность определить тип данных. В строке вызова функции создаётся массив, с помощью конструктора открытого массива, который использует квадратные скобки.

Различия в объектных моделях

Для введения новой объектной модели введено ключевое слово classTurbo Pascal ключевое слово object).

Введены операторы для проверки и приведения классов is и as динамически в ходе выполнения программы. Появились указатели на методы, для чего введено новое использование ключевого слова object:

type
  TMyMethod = procedure (Sender : Object) of object;

Изменения синтаксиса, из-за изменения размещения объектов

В Turbo Pascal можно было работать как с динамическими, так и со статическими экземплярами объектов.

В объектной модели Object Pascal программист работает только с динамическими экземплярами классов, выделяемых в heap-области (куче). В связи с этим изменён синтаксис обращения к полям и методам объектов.

Ранее для работы с динамическими экземплярами объектов, инициализированными с использованием обращения к конструктору в сочетании с функцией New, необходимо было использовать обращение по указателю (^). Теперь тип класса стал являться по умолчанию также указателем.

Пример для сравнения:

Объектная модель в Turbo Pascal:

type
  PMyObject = ^TMyObject;
  TMyObject = object (TObject)
    MyField : PMyType;
    constructor Init;
  end;
//...
var
  MyObject : PMyObject;
begin
  MyObject := New(PMyObject,Init);
  MyObject^.MyField := //...
end;

Новая объектная модель в Object Pascal:

type
  TMyObject = class (TObject)
    MyField : TMyType;
    constructor Create;
  end;
//...
var
  MyObject : TMyObject;
begin
  MyObject := TMyObject.Create;
  MyObject.MyField := //...
end;

Было изменено соглашение об именовании конструкторов и деструкторов. В старой объектной модели вызов New отвечал за распределение памяти, а обращение к конструктору инициализировало выделенную область памяти. В новой модели эти действия выполняет конструктор Create. Начиная с версии Delphi XE появились статические методы класса.[3]

Появилась возможность ограничивать видимость членов класса (методы, свойства), которые предназначены для использования только в реализации производных классов. Это даёт возможность защищать исходный код от модификации пользователями класса. Такие методы содержатся в секции protected (защищённые) в объявлении класса.

Визуальное объектно-ориентированное программирование

Появились понятия свойства (property) и связанные со свойствами ключевые слова read, write, stored, default (nodefault), index. Свойства визуальных объектов, видимых в интегрированной среде разработки, объявляются с помощью нового слова published в качестве секции в объявлении класса, являющегося визуальным объектом.

Обобщения

type
  {объявление}
  generic TList<T> = class
    Items: array of T;
    procedure Add(Value: T);
  end;

implementation
  {реализация}
  procedure TList.Add(Value: T);
  begin
    SetLength(Items, Length(Items) + 1);
    Items[Length(Items) - 1] := Value;
  end;

Общий класс может быть просто специализирован для конкретного типа с использованием ключевого слова specialize:

type
  TIntegerList = specialize TList<Integer>;
  TPointerList = specialize TList<Pointer>;
  TStringList  = specialize TList<string>;

Перегрузка операторов

Разработчики TMT Pascal (модификация Object Pascal) первыми ввели полноценную перегрузку операторов, что впоследствии было перенято разработчиками других диалектов языка: Delphi (с Delphi 2005), Free Pascal и др.

Пример:

{объявление}
type
  TVector = packed record
    A, B, C: Double;
    procedure From(const A, B, C: Double);
    class operator Add(const Left, Right: TVector): TVector;
    class operator Implicit(const v: TVector): TPoint;
  end;

{реализация}
implementation
//...
  class operator TVector.Add(const Left, Right: TVector): TVector;
  begin
    Result.A := Left.A + Right.A;
    Result.B := Left.B + Right.B;
    Result.C := Left.C + Right.C;
  end;

  class operator TVector.Implicit(const v: TVector): TPoint;
  begin
    Result.A := round(v.A);
    Result.B := round(v.B);
  end;
//...

{использование}
var
  v1, v2: TVector;
begin
  v1.From(20, 70, 0);
  v2.From(15, 40, 4);
  Canvas.Polygon([v1, v2, v1 + v2]);
end;

Поддержка различными разработчиками

Начиная с версии среды Delphi 7, фирма Borland стала официально называть язык Object Pascal как Delphi[4].

Язык Object Pascal поддерживается и развивается другими разработчиками. Наиболее серьёзные реализации Object Pascal (помимо Delphi) — это кроссплатформенный TopSpeed Pascal (версия языка Turbo Pascal[5]) мультиязыковой среды TopSpeed, TMT Pascal, Virtual Pascal, PascalABC.NET, Free Pascal, GNU Pascal. Язык программирования Oxygene является диалектом Object Pascal для платформы .NET и дальнейшим его развитием, а новыми возможностями языка является оператор ":", асинхронный и отложенный вызовы методов, асинхронное выполнение блока кода, параллельные циклы, анонимные конструкторы, элементы контрактного и аспектно-ориентированного программирования и др.[6] (компилятор распространяется без ограничений).

Примеры «Hello, world!» в различных объектных расширениях языка

Примечания

  1. (1985) «Object Pascal Report». Structured Language World 9 (3): 10–7.
  2. Буч Г. Объектно-ориентированное проектирование с примерами применения К.: Диалектика; М.: Конкорд, 1992. — 519 с.
  3. Преимущества перехода на Delphi XE Что нового по сравнению с Delphi 7 Андреано Лануш (Andreano Lanusse) Архивная копия от 15 июня 2016 на Wayback Machine,Ноябрь 2010 г. Embarcadero Technologies Россия, СНГ
  4. Delphi Language Overview (недоступная ссылка)
  5. TopSpeed-компиляторы: не дожили до триумфа Архивировано 11 января 2012 года.
  6. Remobjects Oxygene (недоступная ссылка). Дата обращения: 16 ноября 2015. Архивировано 17 ноября 2015 года.
  7. Michaël Van Canneyt. Chapter 6: Classes (англ.) (недоступная ссылка). Free Pascal : Reference guide. (декабрь 2011). Дата обращения: 16 января 2012. Архивировано 2 февраля 2012 года.